package org.carabiner.infinitest;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.TimerTask;

import org.carabiner.infinitest.swingui.DefaultInfinitestMainFrame;
import org.carabiner.infinitest.swingui.EventSupport;
import org.carabiner.infinitest.swingui.HaltTestAction;
import org.carabiner.infinitest.swingui.InfinitestView;
import org.carabiner.infinitest.swingui.ReloadIndexAction;
import org.carabiner.infinitest.swingui.ResultTreeModel;

/**
 * An automated test runner for JUnit Tests.
 * 
 * @author <a href="mailto:benrady@gmail.com"Ben Rady</a>
 */
public class Infinitest implements PropertyChangeListener
{
  private InfinitestCore core;
  private InfinitestView view;

  public Infinitest(InfinitestCore infinitestCore, InfinitestView infinitestView)
  {
    core = infinitestCore;
    view = infinitestView;
    core.addPropertyChangeListener(this);
    updateStatus();
  }

  public void propertyChange(final PropertyChangeEvent evt)
  {
    Runnable runnable = new Runnable()
    {
      public void run()
      {
        handlePropertyChange(evt);
      }
    };
    EventSupport.runThisOnEventThread(runnable);
  }

  private void handlePropertyChange(PropertyChangeEvent evt)
  {
    String propertyName = evt.getPropertyName();
    if (propertyName.equals(DefaultInfinitestCore.TESTS_IN_QUEUE_PROPERTY))
    {
      if (evt.getOldValue().equals(0))
        view.setMaximumProgress((Integer) evt.getNewValue());
      int testsLeftToRun = view.getMaximumProgress() - (Integer) evt.getNewValue();
      view.setProgress(testsLeftToRun);
      return;
    }
    if (propertyName.equals(DefaultInfinitestCore.CURRENT_TEST_PROPERTY))
    {
      view.setCurrentTest((String)evt.getNewValue());
      return;
    }
    if (propertyName.equals(DefaultInfinitestCore.STATUS_PROPERTY))
    {
      Status status = (Status) evt.getNewValue();
      status.updateView(view);
      return;
    }
    throw new IllegalArgumentException("Unknown property name: " + propertyName);
  }

  static InfinitestView createFrame(TestControl core, ResultTreeModel results) throws FileNotFoundException, IOException
  {
    InfinitestView mainFrame = new DefaultInfinitestMainFrame();
    mainFrame.addAction(new ReloadIndexAction(core));
    mainFrame.addAction(new HaltTestAction(core));
    mainFrame.setResultsModel(results);
    return mainFrame;
  }

  private void updateStatus()
  {
    long timeSinceGreen = core.getTimeSincePassingState();
    String timeStamp = InfinitestUtils.formatTime(timeSinceGreen);
    view.setAngerBasedOnTime(timeSinceGreen);
    view.setCycleTime(timeStamp);
    view.setStatusName(core.getStatus().toString());
  }

  public static void main(String[] args) throws IOException
  {
    List<File> classFileDirs = new ArrayList<File>();
    File filterListFile = null;
    for (String arg : args)
    {
      File fileArg = new File(arg);
      if (fileArg.isDirectory())
        classFileDirs.add(fileArg);
      else
        filterListFile = fileArg;
    }
    final DefaultInfinitestCore core = new DefaultInfinitestCore(filterListFile, classFileDirs);
    InfinitestView view = createFrame(core, core.getTestResultModel());
    final Infinitest app = new Infinitest(core, view);

    java.util.Timer coreTimer = new java.util.Timer();
    coreTimer.schedule(new TimerTask()
    {
      public void run()
      {
        core.update();
      }
    }, 100, InfinitestSettings.getRefreshRate());
    javax.swing.Timer statusTimer = new javax.swing.Timer(999, new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        app.updateStatus();
      }
    });
    statusTimer.start();
    app.view.setVisible(true);
  }

  public FilterList getFilters()
  {
    return core.getFilters();
  }

  public void dispose()
  {
    core.dispose();
  }
}
